#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <bitset>
#include <thread>
#include <boost/container/static_vector.hpp>
#include "lock_free_ring.h"

template <class T>
T *CreateConsSharMemory(int nKey, int &shmID)

{
    // 创建共享内存
    shmID = shmget(nKey, 0, 0);
    if (shmID < 0)
    {
        // todo 输出log 共享内存创建失败
        std::cerr << "shmget fail, " << errno << std::endl;
        return nullptr;
    }

    // 映射共享内存到进程地址空间
    T *pDataField = (T *)shmat(shmID, 0, 0);
    if (((void *)(-1)) == (void *)pDataField)
    {
        // 映射失败
        std::cerr << "shmat failed: " << errno << std::endl;
        perror("shmat ");
        return nullptr;
    }

    // 映射成功
    return pDataField;
}

void pop_thread(lock_free_ring<size_t, QUEUE_SIZE> &lrq, std::bitset<TOTAL_COUNT> &data, std::atomic<bool> &stop)
{
    while (true)
    {
        size_t i = 0;
        if (lrq.pop(i))
        {
            data.set(i);
        }
        else
        {
            __builtin_ia32_pause();
            if (stop)
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
                for (size_t i = 0; i < 1000; ++i)
                {
                    if (lrq.pop(i))
                    {
                        data.set(i);
                    }
                }
                break;
            }
        }
    }
}

void print_set(const std::string &title, const std::bitset<TOTAL_COUNT> &data)
{
    std::cout << title << ": [";

    for (size_t i = 0; i < TOTAL_COUNT; ++i)
    {
        if (data.test(i))
        {
            std::cout << i << ",";
            if (i % 20 == 0)
                std::cout << std::endl;
        }
    }

    std::cout << "]" << std::endl;
}

int main()
{
    lock_free_ring_test *pDataField = nullptr;
    int shmID = 0;
    pDataField = CreateConsSharMemory<lock_free_ring_test>(333, shmID);

    std::bitset<TOTAL_COUNT> expect;
    for (size_t i = 0; i < TOTAL_COUNT; ++i)
        expect.set(i, true);

    size_t succ_cnt = 0;

    while (true)
    {
        boost::container::static_vector<std::thread, pop_thread_cnt> pop_threads;
        std::bitset<TOTAL_COUNT> data[pop_thread_cnt];
        for (size_t i = 0; i < pop_thread_cnt; ++i)
            pop_threads.push_back(std::thread(pop_thread, std::ref(pDataField->ring), std::ref(data[i]), std::ref(pDataField->stop)));

        for (size_t i = 0; i < pop_thread_cnt; ++i)
            pop_threads[i].join();

        pDataField->stop = false;

        std::bitset<TOTAL_COUNT> result;
        for (auto &d : data)
        {
            // 判断是否有重复的数据
            auto tmp = d & result;
            if (tmp.any())
            {
                std::cout << "data duplicated" << std::endl;

                // get object index
                auto const index = &d - &data[0];
                std::cout << "duplicated at: " << index << std::endl;

                // print duplicated data
                print_set("duplicate", tmp);
                return -1;
            }

            result |= d;
        }

        if (expect == result)
        {
            succ_cnt++;
            std::cout << "pass " << succ_cnt << '\r' << std::flush;
        }
        else
        {
            std::cout << std::endl;
            std::cout << "expect_count: " << expect.size() << ", result_count: " << result.size() << std::endl;
            std::cout << "fail" << std::endl;
            pDataField->ring.print_info();
            // print_set("expect", expect);
            // print_set("result", result);
            std::bitset<TOTAL_COUNT> diff;

            // diff bitset
            for (size_t i = 0; i < TOTAL_COUNT; ++i)
                if (expect.test(i) != result.test(i))
                    diff.set(i, true);

            print_set("diff", diff);
            return -1;
        }

        pDataField->finish = true;
    }
}